#pragma once
#include <zGraphicsConfig.hpp>
#include <Utility\HasFlag.hpp>
#include <Math\Vector3.hpp>
#include "Mesh.hpp"

namespace zzz {
class ZGRAPHICS_CLASS HalfEdgeMesh {
public:
  struct HalfEdge;
  struct Vertex;
  struct Face;
  //////////////////////////////////////////////////////////////////////////
  struct HalfEdge : public HasFlags {
    HalfEdge *twin_, *prev_, *next_;
    Vertex *start_;
    Face *left_face_;
    bool boundary_;
    bool valid_;

    HalfEdge(bool boundary)
    :boundary_(boundary), twin_(NULL), prev_(NULL), next_(NULL), 
    start_(NULL), left_face_(NULL), valid_(true) {
    }
    Vertex *end_vertex() {
      return next_->start_;
    }
  };
  //////////////////////////////////////////////////////////////////////////
  struct Vertex  : public HasFlags {
    Vector3f pos_;
    HalfEdge *half_edge_;
    zuint index_;   // index of original position
    bool valid_;
    vector<HalfEdge*> adj_edges_;

    Vertex(const Vector3f &pos, zuint idx)
    :pos_(pos), half_edge_(NULL), valid_(true), index_(idx) {
    }
  };
  //////////////////////////////////////////////////////////////////////////
  struct Face {
    HalfEdge *half_edge_;
    bool valid_;
    zuint index_;   // index from original mesh group
    Face(zuint idx)
    :half_edge_(NULL), valid_(true), index_(idx) {
    }
  };

public:
  vector<HalfEdge*> half_edges_;
  vector<HalfEdge*> boundary_half_edges_;
  vector<Vertex*> vertices_;
  vector<Face*> faces_;

  ~HalfEdgeMesh();

  void Clear();
  void LoadTriMeshGroup(const TriMesh &mesh, zuint group);
private:
  inline void ConnectEdges(HalfEdge *he1, HalfEdge *he2);
  inline void SetTwins(HalfEdge *he1, HalfEdge *he2);
  inline void ConnectFaceEdge(Face *f, HalfEdge *e);
};
};  // namespace zzz